#ifndef CHARACTERS_HPP
#define CHARACTERS_HPP

#include <string>
#include <SFML/Graphics.hpp>
#include "Object.hpp"
#include "../Stats.hpp"
#include "../Items/Items.hpp"

namespace OForce_Mode {
class CharacterEvent;
}
namespace OForce_Object {
enum DIRECTION {DOWN = 0,
	LEFT = 1,
	RIGHT = 2,
	UP = 3
};
// Characters are objects
enum CONTROL_TYPE {PLAYER = 0,
	STILL = 1,
	SCRIPTED = 2,
	RANDOM = 3};

// TODO make animations a MAP
class Character : public Object
{
public: 
	Character(float positionx, float positiony, float sizex, float sizey,
			std::string charSheet,
			std::string _name, std::string _class, int _numAnim, int ID);
	~Character();
	void draw();
	void update();
	// Event handler information
	OForce_Mode::CharacterEvent *controlledByEvent;
	void acquireEvent(OForce_Mode::CharacterEvent *event);
	void releaseEvent(OForce_Mode::CharacterEvent *event);
	void saveState();
	void resumeState();
	// basic information
	sf::Vector2i getSize() {return mSize;}
	std::string getName() {return mName;}
	std::string getClass() {return mCharClass;}
	int getFrameSizeX() {return mSize.x;}
	int getFrameSizeY() {return mSize.y;}
	// movement
	void setControlType(CONTROL_TYPE ct) {controlType = ct;}
	DIRECTION getDirection() {return mDir;}
	void setDirection(DIRECTION dir);
	void lookAt(float x, float y);
	void move(float x, float y);
	void setMovementDuration(float t) {mDuration = t;}
	float getMoveSpeed() {return mMoveSpeed;}
	void setMoveSpeed(float s) {mMoveSpeed = s;}
	float getXPosition() {return sprite.getPosition().x;}
	float getYPosition() {return sprite.getPosition().y;}
	// collision
	void setCollide(bool c) {mCollide = c;}
	bool getCollide() {return mCollide;}
	sf::FloatRect getCollisionArea() {return sprite.getGlobalBounds();}
	// Item management
	int getNumItems() {return vItem.size();}
	void addItem(OForce::GenericItem *item);
	void addItem(int itemID);
	OForce::GenericItem *getItem(int slot);
	void removeItem(int slot);
	// dialoguee functions
	void addDialogueByID(int id);
	void initiateDialogue();
	void incrementDialogue();
	void setNextDialogue(int next);
	int getNumDialogue() {return vDialogue.size();}
	// animations
	int getNumAnimations() {return numAnimations;}
	void setNumAnimations(std::vector<int> _vAnim);
	void addAnimFrames(int numFrames);
	void updateAnim(int currentAnim);
	void setAnimDuration(float dur) {animDuration = dur;}
	void setCustomAnimation(std::string file, float t);
	bool isCustomAnimation() {return customInProgress;}
	void endCustomAnimation() {customAnimationTimer = 0.0f;}
	// portrait file for menus/dialogue
	void setPortrait(std::string filename);
	bool getHasPortrait() {return hasPortrait;}
	std::string getPortraitFile() {return portraitFile;}
	// character stats
	Stats *getStats() {return stats;}
	void heal(int x) {stats->heal(x);}
	// Active member: this is only used for party members in battle.
	// This is only really necessary for the GlobalState to keep track of members.
	bool isActiveMember() {return mActive;}
	void setActiveMember(bool b) {mActive = b;}
//	// Whether the character is a part of the main battle party
//	bool isBattleMember() {return mBattle;}
//	void setBattleMember(bool b) {mBattle = b;}
private:
	// Whether or not this character collides with things on the map
	bool mCollide;
	// State information for when controlled by scripts
	bool mStateSaved;
	DIRECTION mSavedDirection;
	CONTROL_TYPE prevType;
	float mSavedSpeed;
	float mMoveSpeed;
	// basic info
	std::string mName;
	std::string mCharClass;
	std::string spriteSheet;
	// A vector which can store up to four items
	std::vector<OForce::GenericItem *> vItem;
	// whether the character is considered an active member.
	// for story reasons, it might be nice to have the option to have a member
	// temporarily leave the team.
	bool mActive;
//	// Whether or not the character is to be brought into the battle field
//	bool mBattle;
	// custom animation
	std::string customAnimation;
	sf::Texture customTexture;
	float customAnimationTimer;
	bool customInProgress;
	// dialogue/menu portrait
	bool hasPortrait;
	std::string portraitFile;
	// Dialogue
	bool hasUnseenDialogue;
	int currentDialogue;
	std::vector<int> vDialogue;
	// All characters that can move should have at least four animations
	int numAnimations;
	int currentFrame;
	int currentAnim;
	// timers
	float timer; // animation timer
	float mDuration; // duration of walking
	float mRandomCooldown; // duration to wait in between random paths
	float animDuration;
	std::vector<int> vNumFrames;
	// character stats:
	Stats *stats;
	// direction and control
	DIRECTION mDir;
	// NPC movement
	CONTROL_TYPE controlType;
	void randomDirection();
	float distanceMoved();
	void moveToNextPosition();
};

} // namespace OForce_Object
#endif
